package xyz.xtt.gateway.third;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Objects;
import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import cn.hutool.core.lang.TypeReference;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.gateway.cons.Cons;

@RefreshScope
@Component
@Slf4j
public class ThirdTokenCheck {
	public static enum DeviceType {
		UNKNOWN(0), IOS(1), ANDROID(2), WEB(3), PC(4), MAC(5);

		private int type;

		DeviceType(int type) {
			this.type = type;
		}

		public String type() {
			return String.valueOf(type);
		}
	}

	public static enum AppType {
		All(0, "ALL"), TONG_TONG(1, "通通");

		private int type;
		private String desc;

		AppType(int type, String desc) {
			this.type = type;
			this.desc = desc;
		}

		public String type() {
			return String.valueOf(type);
		}

		public String desc() {
			return desc;
		}
	}

	public static enum LoginType {
		APP(1), WEB(2), SDK(3), PC(4);

		private int type;

		LoginType(int type) {
			this.type = type;
		}

		public String type() {
			return String.valueOf(type);
		}
	}

	@Data
	@Builder
	@AllArgsConstructor
	@NoArgsConstructor
	public static class ResponseResult<T> {
		private Integer code;
		private T data;

		public boolean isOK() {
			return Objects.equals(code, 0);
		}
	}

	@Data
	@Builder
	@NoArgsConstructor
	@AllArgsConstructor
	public static class UserResource {
		private String id;
		private String firstName;
		private String phoneNumber;
		private String gender;
		private Boolean deleted;
		private Integer appType;
		private Integer registerDays;
		private String uniqueName;
		private String imUserId;
		private String shareLink;
		private String payPasswordStatus;
		private Boolean aiRole;
		private Integer type;
		private Long createdAt;
	}

	@Data
	@Builder
	@NoArgsConstructor
	@AllArgsConstructor
	public static class UserData {
		private UserResource userResource;
	}

	@Data
	@Builder
	@NoArgsConstructor
	@AllArgsConstructor
	public static class ResponseText {
		private int code;
		private UserData data;

		public boolean ok() {
			return code == 0;
		}
	}

	@Value("${third.auth.moreLog:false}")
	private Boolean authMoreLog;

	@Value("${third.auth.connectTimeoutSec:30}")
	private Long connectTimeoutSec;

	@Value("${third.auth.requestTimeoutSec:10}")
	private Long requestTimeoutSec;
//
//	@Value("${token.check.url}")
//	private String tokenCheckUrl;

	@Value("${token.newCheck.url}")
	private String newTokenCheckUrl;

	@Value("${user.info.thirdAuthCode}")
	private String thirdAuthCode;

	public String newCheck(URI requestUrl, String token, String sign, String version, String deviceId, String loginType, String appType, String device,
			String lang) throws ThirdTokenInvalidException, ThirdTokenLimitedException, ThirdSignInvalidException, ThirdTokenExpirationException {
		String url = String.format(newTokenCheckUrl, token);
		HttpRequest request = HttpRequest
				.newBuilder()
				.uri(URI.create(url))
				.header(Cons.AUTHORIZATION, thirdAuthCode)
				.header("Content-Type", "application/json")
				.header("login-type", "1")
				.header("jsvnr", "true")
				.timeout(Duration.ofSeconds(10))
				.GET()
				.build();
		String uid = StringUtils.EMPTY;
		try {
			HttpClient client = HttpClient.newHttpClient();
			HttpResponse<String> send = client.send(request, HttpResponse.BodyHandlers.ofString());
			int statusCode = send.statusCode();
			String body = send.body();
			if (authMoreLog) {
				log
						.info("newCheck third request requestUrl:{}, tokenCheckUrl:{}, authorization:{}, sign:{}, version:{}, device-id:{}, login-type:{}, app-type:{}, device:{}", requestUrl, url, token, sign, version, deviceId, loginType, appType, device);
				log.info("third response: {}", body);
			}
			if (Objects.equals(HttpStatus.HTTP_OK, statusCode)) {
				ResponseResult<UserResource> data = JSONUtil.toBean(body, new TypeReference<ResponseResult<UserResource>>() {
				}, false);
				uid = Optional.ofNullable(data).filter(ResponseResult::isOK).map(ResponseResult::getData).map(UserResource::getId).orElse(StringUtils.EMPTY);
				if (Objects.isNull(data)) {
					log.info("third data JSONUtil.toBean is null response: {}", body);
					return StringUtils.EMPTY;
				}
				if (StringUtils.isNotBlank(uid)) {
					return uid;
				}
				log.info("url:{},uid:{},statusCode:{}", url, uid, statusCode);
				Integer code = data.getCode();
				if (Objects.equals(701001, code)) {
					log.info("third data.code == 701001 response: {}", body);
					throw new ThirdTokenLimitedException("token受限");
				}
				if (Objects.equals(301005, code)) {
					log.info("third data.code == 301005 response: {}", body);
					throw new ThirdSignInvalidException("sign错误");
				}
				if (Objects.equals(101006, code)) {
					log.info("third data.code == 101006 response: {}", body);
					throw new ThirdTokenExpirationException("token过期");
				}
				if (!Objects.equals(0, code)) {
					log.info("third data.code != 0 response: {}", body);
					throw new ThirdTokenInvalidException("token失效");
				}

			} else {
				log.info("url:{},body:{},statusCode:{}", url, body, statusCode);
			}
		} catch (IOException | InterruptedException e) {
			log.info("ex:{}", e.getMessage(), e);
		}
		return null;
	}

//	public String check(URI requestUrl, String token, String sign, String version, String deviceId, String loginType, String appType, String device,
//			String lang) throws ThirdTokenInvalidException, ThirdTokenLimitedException, ThirdSignInvalidException, ThirdTokenExpirationException {
//		HttpClient client = HttpClient
//				.newBuilder()
//				.followRedirects(Redirect.NORMAL)
//				.connectTimeout(Duration.ofSeconds(connectTimeoutSec))
//				.version(Version.HTTP_1_1)
//				.build();
//		HttpRequest request = HttpRequest
//				.newBuilder()
//				.uri(URI.create(tokenCheckUrl))
//				.header(Cons.AUTHORIZATION, token)
//				.header(Cons.SIGN, sign)
//				.header(Cons.VERSION, version)
//				.header(Cons.DEVICE_ID, deviceId)
//				.header(Cons.LOGIN_TYPE, loginType)
//				.header(Cons.APP_TYPE, appType)
//				.header(Cons.DEVICE, device)
//				.header(Cons.LANG, lang)
//				.timeout(Duration.ofSeconds(requestTimeoutSec))
//				.GET()
//				.build();
//		try {
//			String body = client.send(request, HttpResponse.BodyHandlers.ofString()).body();
//			if (authMoreLog) {
//				log
//						.info("check third request requestUrl:{}, tokenCheckUrl:{}, authorization:{}, sign:{}, version:{}, device-id:{}, login-type:{}, app-type:{}, device:{}", requestUrl, tokenCheckUrl, token, sign, version, deviceId, loginType, appType, device);
//				log.info("third response: {}", body);
//			}
//			ResponseText data = JSONUtil.toBean(body, ResponseText.class);
//			if (Objects.isNull(data)) {
//				log.info("third data JSONUtil.toBean is null response: {}", body);
//				return null;
//			}
//			int code = data.code;
//			if (Objects.equals(701001, code)) {
//				log.info("third data.code == 701001 response: {}", body);
//				throw new ThirdTokenLimitedException("token受限");
//			}
//			if (Objects.equals(301005, code)) {
//				log.info("third data.code == 301005 response: {}", body);
//				throw new ThirdSignInvalidException("sign错误");
//			}
//			if (Objects.equals(101006, code)) {
//				log.info("third data.code == 101006 response: {}", body);
//				throw new ThirdTokenExpirationException("token过期");
//			}
//			if (!Objects.equals(0, code)) {
//				log.info("third data.code != 0 response: {}", body);
//				throw new ThirdTokenInvalidException("token失效");
//			}
//			String userId = Optional
//					.ofNullable(data)
//					.filter(ResponseText::ok)
//					.map(ResponseText::getData)
//					.map(UserData::getUserResource)
//					.map(UserResource::getId)
//					.filter(StringUtils::isNotBlank)
//					.orElse(null);
//			return userId;
//		} catch (IOException | InterruptedException e) {
//			log.error("third login IOException | InterruptedException ex: {}", e.getMessage(), e);
//		} catch (Exception e) {
//			log.error("third login Exception ex: {}", e.getMessage(), e);
//			throw e;
//		}
//		return StringUtils.EMPTY;
//	}

}
